package com.cci.kangdao.wechatOrder.service.impl;

import com.cci.kangdao.azureAD.AzureADTool;
import com.cci.kangdao.azureAD.ManagementToken;
import com.cci.kangdao.cipapi.CipServiceApi;
import com.cci.kangdao.common.RedisKeys;
import com.cci.kangdao.dao.LoginDao;
import com.cci.kangdao.dao.RolesTDao;
import com.cci.kangdao.dao.UserTDao;
import com.cci.kangdao.dao.UserTokenTMapper;
import com.cci.kangdao.dao.model.UserT;
import com.cci.kangdao.dao.model.UserTokenT;
import com.cci.kangdao.externalData.dto.request.LyhFileUserRequest;
import com.cci.kangdao.externalData.service.ExternalDataSynchroService;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.service.PropertiesUtils;
import com.cci.kangdao.service.impl.RolesServiceImpl;
import com.cci.kangdao.utilTool.*;
import com.cci.kangdao.wechatOrder.constants.WeChatConstants;
import com.cci.kangdao.wechatOrder.dao.UserOutSideTokenTDao;
import com.cci.kangdao.wechatOrder.dao.WeChatUserRelationTDao;
import com.cci.kangdao.wechatOrder.dto.request.UserCheckRequest;
import com.cci.kangdao.wechatOrder.dto.response.WeChatLoginResponse;
import com.cci.kangdao.wechatOrder.enums.CompanyEnum;
import com.cci.kangdao.wechatOrder.enums.UserPhoneRegistStatus;
import com.cci.kangdao.wechatOrder.exception.*;
import com.cci.kangdao.wechatOrder.model.UserOutSideTokenT;
import com.cci.kangdao.wechatOrder.model.WeChatUserRelationT;
import com.cci.kangdao.wechatOrder.model.wx.WxAppInfo;
import com.cci.kangdao.wechatOrder.service.IOutSideTokenService;
import com.cci.kangdao.wechatOrder.service.IUserCheckService;
import com.cci.kangdao.wechatOrder.util.wxsdk.WxUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @description: 用户信息校验服务实现类
 * @author: zyf
 * @create: 2021-03-12
 */
@Service
public class UserCheckServiceImpl implements IUserCheckService {

    private Logger log = Logger.getLogger(this.getClass().getName());


    @Resource
    private UserTDao userTDao;

    @Resource
    private UserTokenTMapper userTokenTMapper;
    @Resource
    private LoginDao loginDao;
    @Resource
    private PropertiesUtils propertiesUtils;
    @Autowired
    private RedisClientUtils redisClientUtils;
    @Resource
    private RolesServiceImpl rolesService;

    @Resource
    private RolesTDao rolesTDao;

    @Autowired
    private IOutSideTokenService iOutSideTokenService;

    /**
     * 用户外部Token
     */
    @Resource
    private UserOutSideTokenTDao userOutSideTokenTDao;

    @Resource
    private WeChatUserRelationTDao weChatUserRelationTDao;

    @Resource
    private IOutSideTokenService outSideTokenService;
    @Resource
    private CipServiceApi cipServiceApi;
    @Resource
    private ExternalDataSynchroService externalDataSynchroService;

    @Override
    public ModelAndView checkUser(UserCheckRequest userCheckRequest, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String,Object> result = new HashMap<>();
        Object data = null;
        result.put("status", 0);
        result.put("msg", "用户成功登陆");
        if (userCheckRequest.getUserSource() ==  null){
            throw new NotCheckException("用户来源不能为空");
        }
        //
        switch (userCheckRequest.getUserSource()){
            case 1:
                data = checkUserByTb(userCheckRequest);
                break;
            case 2:
                data = checkUserByWeChat(userCheckRequest,request);
                break;
            default:
                data = new HashMap<>();
                break;
        }

        if (data ==null){
            result.put("status", 1);
            result.put("msg", "终端用户未找到此手机号");
        }else{
            result.put("data",data);
        }
        ParameterTool.writeResponse(response, JsonUtils.toJsonString(result));
        return null;
    }


    /**
     * 按三兄弟方式进行用户检测
     * @param userCheckRequest
     * @return
     */
    private Map<String,Object> checkUserByTb(UserCheckRequest userCheckRequest)throws Exception{
        Map<String,Object> result = new HashMap<>();
        if (StringUtils.isBlank(userCheckRequest.getPhone())){
            throw new NotCheckException("用户手机号不能为空");
        }

        UserT user = userTDao.checkUserByNameOrPhone(userCheckRequest.getPhone());
        if (user != null){
            result.put("userName",user.getUserName());
            result.put("systemTime", LocalTimeUtil.getRealCurrentTime().replace("-","").replace(":","").replace(" ",""));
            return result;
        }

        return null;
    }

    /**
     * 用户登陆检测-微信
     * @param userCheckRequest
     * @return
     * @throws Exception
     */
    private WeChatLoginResponse checkUserByWeChat(UserCheckRequest userCheckRequest, HttpServletRequest request)throws Exception{
        WeChatLoginResponse loginResponse = new WeChatLoginResponse();

        UserOutSideTokenT headerToken = getCheckHeaderToken(userCheckRequest);

        if (StringUtils.isBlank(userCheckRequest.getCode())){
            throw new NotCheckException(-99,"微信返回的CODE不能为空");
        }
        //判断是否为有效渠道
        WxAppInfo info=  WxUtils.getWxAppInfo(userCheckRequest.getCompanyID().intValue());
        if (info== null){
            throw new NotCheckException(-99,"微信未找到渠道相关信息");
        }
        //获取OPENID
        ManagementToken managementToken =  WxUtils.getTokenByCode(info.getAppId(),info.getSecret(),userCheckRequest.getCode());
        if (StringUtils.isBlank(managementToken.getOpenid())){
            throw new NotCheckException(-99,"无法获取OPENID,请刷新重试");
        }
//        ManagementToken managementToken = new ManagementToken();
//        managementToken.setOpenid("oMKRcwRLfzYtSck96_rIrVlTnnBM");
                headerToken.setOutSideID(managementToken.getOpenid());
        loginResponse.setOpenId(managementToken.getOpenid());
        //判断是否已经绑定手机号
        UserT user = weChatUserRelationTDao.selectUserByOpenId(managementToken.getOpenid(),userCheckRequest.getCompanyID());
        if (user == null){
//            throw new NotCheckException("当前微信ID未注册相关用户");
            if (null != userCheckRequest.getCompanyID() && userCheckRequest.getCompanyID() == 3) {
                //产生新的token
                UserOutSideTokenT tokenT = outSideTokenService.generateToken(headerToken, new UserT());
                //获取token
                loginResponse.setToken(tokenT.getToken());
                return loginResponse;
            } else {
                loginResponse.setToken("");
                loginResponse.setStatus(0);
                return loginResponse;
            }
        }

        loginResponse.setUserId(user.getId());
        //判断是否有效终端用户
        Integer isTerminal = rolesTDao.getRoleNumByOpenID(user.getId(), managementToken.getOpenid(), userCheckRequest.getCompanyID(), "R0002");
        //判断是否为终端用户角色
        if (isTerminal == null || isTerminal == 0) {
            loginResponse.setStatus(2);
            throw new NotCheckException(WeChatConstants.NOT_TERMINAL_MESSAGE);
        }

        UserOutSideTokenT userOutSideTokenT = userOutSideTokenTDao.selectByOutSideIdAndCompanyId(managementToken.getOpenid(), userCheckRequest.getCompanyID());
        //验证是否登录
        if (userCheckRequest.getCompanyID() != 3 && Objects.isNull(userOutSideTokenT)) {//排除dcec的渠道
            //未登录的话，跳到登录页面
            loginResponse.setToken("");
            loginResponse.setStatus(0);
            return loginResponse;
        }
        UserOutSideTokenT tokenT = outSideTokenService.generateToken(headerToken, user);
        //获取token
        loginResponse.setToken(tokenT.getToken());
        loginResponse.setStatus(1);
        //追加用户手机号
        loginResponse.setPhone(user.getPhone());
        loginResponse.setContact(user.getContact());
        return loginResponse;
    }






    //外部用户注册接口
    @Override
    public ModelAndView outsideUserRegister(Map<String, Object> map) {
        HttpServletResponse response = (HttpServletResponse) map.get("response");
        JSONObject obj = new JSONObject();
        String mobile = MapUtils.getString(map, "mobile", "");
        mobile = AESTool.decryptString(mobile); //解密


        try {

            String verifyCode = MapUtils.getString(map, "verifyCode", "");
            String contact = MapUtils.getString(map, "contact", "");
            //用户来源 0:e路康明斯注册用户，1:三兄弟注册用户，2:微信公众号注册用户
            int userSource = MapUtils.getIntValue(map, "userSource", -1);

            String pwd = NumberUtils.getStringRandom(8); //设置默认密码
            //验证手机号，验证码，真实姓名,用户来源是否为空
            if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(verifyCode)
                    || StringUtils.isEmpty(contact) || userSource == -1) {
                obj.put("status", -5);
                obj.put("msg", ApiErrorCode.getInstance().getErrorMsg(-5));
                ParameterTool.writeResponse(response, obj.toString());
                obj = null;
                return null;
            }
            Object typeLock = redisClientUtils.getObject("sms-lock-" + mobile);
            if (null != typeLock) {
                com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(typeLock.toString());
                Integer locktimeRedis = jsonObject.getInteger("locktime");
                String currentDate = jsonObject.getString("currentDate");
                boolean before = LocalTimeUtil.isBefore(LocalTimeUtil.getTimeAfterSeconds(currentDate, locktimeRedis * 60), LocalTimeUtil.getRealCurrentTime());
                if (!before) {
                    redisClientUtils.delkey("sms" + mobile);
                    ParameterTool.writeErrorResponse(response, -55, "您已连续输错多次，请" + LocalTimeUtil.turnDayHourMinuteString((int) locktimeRedis) + "后再试！");
                    return null;
                }
            }

            if (!validateVerifyCode(mobile, verifyCode)) {
                int timeMax = 5;
                int times = this.smsCodeTimes(mobile, timeMax);
                if (times >= timeMax) {
                    //添加  输错6次后，5min后在重试，从第7次开始等待时间翻倍，直至输入成功后，恢复正常时间。
                    int locktime = 5;
                    Map<String, Object> lockMap = new HashMap<>();
                    Object type = redisClientUtils.getObject("sms-lock-" + mobile);
                    if (null != type) {
                        com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(type.toString());
                        Integer locktimeRedis = jsonObject.getInteger("locktime");
                        locktime = 2 * locktimeRedis;
                    }
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("locktime", locktime);
                    jsonObject.put("currentDate", LocalTimeUtil.getRealCurrentTime());
                    redisClientUtils.setObject("sms-lock-" + mobile, jsonObject, 0);
                    redisClientUtils.delkey("sms" + mobile);
                    if (times == 5) {
                        ParameterTool.writeErrorResponse(response, -55);
                        return null;
                    } else {
                        ParameterTool.writeErrorResponse(response, -55, "您已连续输错多次，请" + LocalTimeUtil.turnDayHourMinuteString(locktime) + "后再试！");
                        return null;
                    }
                }
                ParameterTool.writeErrorResponse(response, -6);
                return null;
            } else {
                redisClientUtils.delkey("sms-lock-" + mobile);
                redisClientUtils.delkey("smsTimes" + mobile);
                redisClientUtils.delkey("sms" + mobile);
            }


            // 加锁处理，避免发生多次注册。
            if (!redisClientUtils.lock("outsideUserRegisterLock-" + mobile, 60L)) {
                ParameterTool.writeErrorResponse(response, -98);
                return null;
            }

            UserPhoneRegistStatus registStatus = null;
            // 非微信公众号注册用户
            if (userSource != 2) {
                // 查询用户信息
                boolean userInfo = hasUserInfo(response, mobile);
            	// 为true说明当前手机号已注册
            	if(userInfo) {
            		return null;
            	}
            }else {
            	// 微信公众号注册用户
            	try {
                    Long companyID = MapUtils.getLong(map, "companyID");
                    registStatus = userCheckForWX(MapUtils.getString(map, "openId"), mobile, MapUtils.getString(map, "token"), companyID);
				} catch (TerminateRegistException e) {
					log.error("注册终止异常：message" + e.getMessage());
					ParameterTool.writeResponse(response, e.getCode(), e.getMessage());
					return null;
				}
            }

            Map<String, Object> responseMap = new HashMap<>();
            responseMap.put("status", 0);
            responseMap.put("msg", "success");
            /**
             * 1.非微信公众号注册用户
             * 2.微信公众号注册，但手机号为未注册状态
             */
            if(userSource != 2 || registStatus == UserPhoneRegistStatus.PHONE_UNREGIST) {
	            //在AD中增加用户
	            String webClient_id = this.propertiesUtils.getPropertiesValue("webClient_id");
	            String webClientSecret = this.propertiesUtils.getPropertiesValue("webClientSecret");
	            String tenant = this.propertiesUtils.getPropertiesValue("tenant");
	            //获取token
	            String token = AzureADTool.getManagementToken(tenant, webClient_id, webClientSecret);
	            if (null == token) {
	                ParameterTool.writeErrorResponse(response);
	                return null;
	            }

	            String userJson = AzureADTool.getUser(mobile, tenant, token);
	            if (StringUtils.isEmpty(userJson)) {
	                // 2、Azure AD使用token去新建用户
	                userJson = AzureADTool.addUser(mobile, pwd, tenant, token);
	                if (StringUtils.isEmpty(userJson)) {
	                    ParameterTool.writeErrorResponse(response);
	                    return null;
	                }
	            }


	            /**
	             * 3、保存用户数据到数据库
	             *  并给用户添加默认用户组、子用户组、角色
	             */
	            JSONObject jsonObj = new JSONObject(userJson);
	            String username = jsonObj.getString("userPrincipalName");
	            String adUserId = jsonObj.getString("id");
	            //插入用户数据
                UserT bean = new UserT();
                bean.setAduserId(adUserId);
                //bean.setCompanyId(Long.valueOf(organizationId));
                bean.setUserName(mobile);
                bean.setContact(contact);
                bean.setAzureToken("");
                bean.setPhone(mobile);
                bean.setType(1);
                bean.setEmail("");
                bean.setEmployeeNum("");
                if (userSource == 2) {
                    Integer companyID = MapUtils.getInteger(map, "companyID", -1);
                    bean.setOfficialAccountSource(companyID);
                }
                //获取用户组
                bean = rolesService.initBaseUserGroup(bean);
                int flag = loginDao.insertUserAddSeat(bean);
                if (flag <= 0) {
                    //返回客户
                    ParameterTool.writeErrorResponse(response, -99);
                    return null;
                }
                //修改用户来源字段
                int num = loginDao.updateUserSourceById(userSource, bean.getId());

	            rolesService.initBaseRoles(bean);

                //添加新手活动
                log.info("添加新手活动；userId:" + bean.getId());
                cipServiceApi.addNeophyteUser(bean.getId());
                //注册时接收老友会用户
                LyhFileUserRequest userRequest = new LyhFileUserRequest();
                userRequest.setUserId(bean.getId());
                userRequest.setPhone(bean.getPhone());
                externalDataSynchroService.receiveLyhUser(userRequest);
                /**
                 * 把新生成的用户跟当前微信进行绑定
                 */
                if(registStatus == UserPhoneRegistStatus.PHONE_UNREGIST) {
                    Long companyID = MapUtils.getLong(map, "companyID");
                    if(companyID==3){
                        iOutSideTokenService.registerWeChatUser(MapUtils.getString(map, "openId"), MapUtils.getString(map, "token"), bean, companyID);
                    }else {
                        this.savaWechart(bean, companyID, MapUtils.getString(map, "openId"));
                    }
                }

	            if(userSource != 2) {
		            String accessToken = remoteInitToken(username, pwd);
		            if (StringUtils.isEmpty(accessToken)) {
		                ParameterTool.writeErrorResponse(response);
		                return null;
		            }
		            mergeToken(bean.getId(), adUserId, accessToken);
                    bean = loginDao.getUserByUserId(bean.getId());

                    Map<String, Object> responseDataMap = new HashMap<>();
                    responseDataMap.put("userName", bean.getUserName());
                    responseDataMap.put("systemTime", LocalTimeUtil.getRealCurrentTime().replace("-", "").replace(":", "").replace(" ", ""));
                    responseMap.put("data", responseDataMap);
                }
            }

            // 微信公众号注册用户响应
            if (userSource == 2) {
                UserT user = userTDao.checkUserByNameOrPhone(mobile);
                //查询token
                Long companyID = MapUtils.getLong(map, "companyID");
                UserOutSideTokenT openId = userOutSideTokenTDao.selectByOutSideIdAndCompanyId(map.get("openId").toString(), companyID);
                WeChatLoginResponse loginResponse = new WeChatLoginResponse();
                loginResponse.setOpenId(map.get("openId").toString());
                loginResponse.setStatus(1);
                loginResponse.setUserId(user.getId());
                loginResponse.setPhone(user.getPhone());
                loginResponse.setContact(user.getContact());
                loginResponse.setToken(openId.getToken());
                responseMap.put("data", loginResponse);
            }
            ParameterTool.writeResponse(response, JsonUtils.toJsonString(responseMap));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            ParameterTool.writeErrorResponse(response);
        } finally {
            redisClientUtils.delkey("outsideUserRegisterLock-" + mobile);
        }
        return null;
    }

    public int smsCodeTimes(String mobile, int timeMax) {
        String key = "smsTimes" + mobile;
        String times = (String) redisClientUtils.get(key);
        int timeInt = 0;
        if (StringUtils.isNotBlank(times)) {
            timeInt = Integer.valueOf(times);
        }
        int timesV = timeInt + 1;
        if (timesV <= timeMax) {
            redisClientUtils.set(key, String.valueOf(timesV), 0);
        }
        return timesV;
    }


    /**
     * 微信公众号校验
     *
     * @param openId
     * @param mobile
     * @param token
     * @return
     * @throws Exception
     */
    private UserPhoneRegistStatus userCheckForWX(String openId, String mobile, String token, Long companyID) throws Exception {
    	 // 微信公众号注册用户
    	try {
    		Map<String, Object> map = new HashMap<>();
            map.put("mobile", AESTool.encryptString(mobile));
            map.put("openId", openId);
            map.put("companyID", companyID);
            checkPhoneBeforeRegistWX(map);
        } catch (RegistParameterException | NonNormalUserException e) {
            // 抛此异常表示终止注册
            throw new TerminateRegistException(e.getCode(), e.getMessage());
        } catch (UserCheckException e1) {
            int code = e1.getCode();
            switch (code) {
                case 11:
                    UserT user = userTDao.checkUserByNameOrPhone(mobile);
                    if (companyID != 3) {
                        //去除旧关系
                        this.updateUserOutSideToken(null, openId, companyID, user.getId());
                        //添加新关系
                        this.savaWechart(user, companyID, openId);
                    }else {
                        // 当前手机号未绑定当前公众号，去绑定公众号 可以去注册
                        iOutSideTokenService.registerWeChatUser(openId, token, user, companyID);
                    }
                    return UserPhoneRegistStatus.REGISTED_UNRELATION;
                case 12:
                    // 抛此异常表示终止注册
                    if (companyID == 3) {
                        throw new TerminateRegistException(e1.getCode(), e1.getMessage());
                    } else {
                        //刷新token
                        user = userTDao.checkUserByNameOrPhone(mobile);
                        this.saveOrUpdateUserOutSideTokenT(user, companyID, openId);
                        return UserPhoneRegistStatus.REGISTED_SUCCESS;
                    }
                case 13:
                    // 当前手机号已绑定公众号，去换绑公众号  可以去注册
                    user = userTDao.checkUserByNameOrPhone(mobile);
                    WeChatUserRelationT userRelation = weChatUserRelationTDao.selectByUserIdAndCompanyID(user.getId(), companyID);
                    if (companyID == 3) {
                        iOutSideTokenService.replaceWeChatUser(openId, userRelation.getOpenID(), token, user);
                    } else {
                        //去除关系
                        this.updateUserOutSideToken(user.getId(), openId, companyID, user.getId());
                        //添加关系
                        this.savaWechart(user, companyID, openId);
                    }
                    return UserPhoneRegistStatus.REGISTED_RELATION;
            }
        }
        // 未抛异常时当前手机号未注册 可以去注册
        return UserPhoneRegistStatus.PHONE_UNREGIST;
    }

    /**
     * 保存用户和 微信的关系， 并保存token的信息
     *
     * @param user
     * @param companyID
     * @param openId
     */
    public void savaWechart(UserT user, Long companyID, String openId) {
        //添加关系
        WeChatUserRelationT relationT = new WeChatUserRelationT();
        relationT.setUserId(user.getId());
        relationT.setCompanyID(companyID);
        relationT.setOpenID(openId);
        relationT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
        relationT.setCreator(user.getId());
        weChatUserRelationTDao.insert(relationT);
        //刷新token
        this.saveOrUpdateUserOutSideTokenT(user, companyID, openId);
    }

    public void saveOrUpdateUserOutSideTokenT(UserT user, Long companyID, String openId) {
        UserOutSideTokenT userOutSideTokenT = userOutSideTokenTDao.selectByOutSideIdAndCompanyId(openId, companyID);
        if (null == userOutSideTokenT) {
            this.saveUserOutSideTokenT(user, companyID, openId);
        } else {
            userOutSideTokenT.setUpdateTime(LocalTimeUtil.getRealCurrentTime());
            userOutSideTokenT.setUserId(user.getId());
            Integer redisCacheTime = Integer.valueOf(propertiesUtils.getPropertiesValue("redisCacheTime"));
            userOutSideTokenT.setExpireTime(LocalTimeUtil.getRealExpireTime(redisCacheTime.longValue()));
            userOutSideTokenTDao.updateTokenByOutSideId(userOutSideTokenT);
        }
    }

    public void saveUserOutSideTokenT(UserT user, Long companyID, String openId) {
        UserOutSideTokenT userOutSideTokenT = new UserOutSideTokenT();
        userOutSideTokenT.setUserId(user.getId());
        String userKey = RedisKeys.outSideToken(companyID, 1, openId);
        userOutSideTokenT.setCompanyId(companyID);
        userOutSideTokenT.setSourceType(1);
        userOutSideTokenT.setOutSideID(openId);
        Integer redisCacheTime = Integer.valueOf(propertiesUtils.getPropertiesValue("redisCacheTime"));
        userOutSideTokenT.setToken(TokenUtils.getToken(userKey, redisCacheTime.longValue()));
        userOutSideTokenT.setExpireTime(LocalTimeUtil.getRealExpireTime(redisCacheTime.longValue()));
        userOutSideTokenT.setVersion("0");
        userOutSideTokenT.setFlag(0);
        userOutSideTokenT.setCreator(user.getId());
        userOutSideTokenT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
        userOutSideTokenTDao.insert(userOutSideTokenT);
        redisClientUtils.setObject(RedisKeys.tokenKey(userOutSideTokenT.getToken()), userOutSideTokenT, redisCacheTime);
    }

    /**
     * 去除旧 微信和用户的关系，以及token
     *
     * @param deleteUserId
     * @param deleteOpenId
     * @param companyID
     * @param userId
     */
    public void updateUserOutSideToken(Long deleteUserId, String deleteOpenId, Long companyID, Long userId) {
        //将 原有user绑车的逻辑清除，并去除token
        if (null != deleteUserId) {
            WeChatUserRelationT weChatUserRelationT = weChatUserRelationTDao.selectByUserId(userId, companyID);
            if (null != weChatUserRelationT) {
                this.updateUserOutSideToken(weChatUserRelationT, userId);
            }
        }
        //将 原有openId绑车的逻辑清除，并去除token
        if (StringUtils.isNotBlank(deleteOpenId)) {
            WeChatUserRelationT weChatUserRelationT = weChatUserRelationTDao.selectByOpenIdNotCompanyId(deleteOpenId, companyID);
            if (null != weChatUserRelationT) {
                this.updateUserOutSideToken(weChatUserRelationT, userId);
            }
        }

    }

    /**
     * 去除旧的关系。以及旧的token
     *
     * @param weChatUserRelationT
     * @param userId
     */
    public void updateUserOutSideToken(WeChatUserRelationT weChatUserRelationT, Long userId) {
        weChatUserRelationT.setFlag(-1);
        weChatUserRelationT.setUpdator(userId);
        weChatUserRelationT.setUpdateTime(LocalTimeUtil.getRealCurrentTime());
        weChatUserRelationTDao.updateRelationTStatusByOpenId(weChatUserRelationT);
        //去除redis 中的关系
        String userKey = RedisKeys.outSideToken(weChatUserRelationT.getCompanyID(), 1, weChatUserRelationT.getOpenID());
        redisClientUtils.delkey(userKey);

        //去除    token
        UserOutSideTokenT userOutSideTokenT = userOutSideTokenTDao.selectByOutSideIdAndUserId(weChatUserRelationT.getOpenID(), weChatUserRelationT.getUserId(), weChatUserRelationT.getCompanyID());
        //数据库中不存在则抛出异常
        if (null != null) {
            userOutSideTokenTDao.updateDeleteFlag(userOutSideTokenT.getId());
            //去除redis 中的   token
            redisClientUtils.delkey(RedisKeys.tokenKey(userOutSideTokenT.getToken()));
        }
    }

    private boolean hasUserInfo(HttpServletResponse response, String mobile) {
        // 查询用户信息
        List<UserT> userTList = loginDao.getUserByPhone(mobile);
        if (CollectionUtils.isNotEmpty(userTList)) {
            ParameterTool.writeErrorResponse(response, -4);
            return true;
        } else {
            UserT existT = loginDao.getUserByUserName(mobile);
            if (null != existT) {
                ParameterTool.writeErrorResponse(response, -4);
                return true;
            }
        }
        return false;
    }






    @Transactional
    @Override
    public void refreshToken(HttpServletRequest request, HttpServletResponse response)throws Exception {
        WeChatLoginResponse loginResponse = new WeChatLoginResponse();
        UserOutSideTokenT headerToken = getHeaderToken(request);
        //查询旧token是否存在数据库中
        UserOutSideTokenT tokenT = userOutSideTokenTDao.selectByToken(headerToken.getOutSideID(),headerToken.getToken());
        //获取用户信息
        UserT userT = weChatUserRelationTDao.selectUserByOpenId(headerToken.getOutSideID(),headerToken.getCompanyId());
        //数据库中不存在则抛出异常
        if (tokenT == null || StringUtils.isBlank(tokenT.getOutSideID())){
            throw new NotCheckException("当前用户未获取有效TOKEN请重新登陆");
        }

        if (userT == null){
            throw new NotCheckException("未获取用户信息请确认是否已经登陆");
        }
        //产生新的token
        outSideTokenService.generateToken(tokenT,userT);
        loginResponse.setToken(tokenT.getToken());
        loginResponse.setUserId(userT.getId());
        loginResponse.setOpenId(tokenT.getOutSideID());
        loginResponse.setStatus(1);
        ParameterTool.writeSuccessResponse(response,loginResponse);
    }

    /**
     *
     * @param userCheckRequest
     * @return
     * @throws Exception
     */
    private UserOutSideTokenT getCheckHeaderToken(UserCheckRequest userCheckRequest) throws Exception{
        UserOutSideTokenT tokenT = new UserOutSideTokenT();

        if (userCheckRequest.getCompanyID()==null) {
            throw new NotCheckException("渠道不能为空");
        }
        else if (userCheckRequest.getType()==null) {
            throw new NotCheckException("类型不能为空");
        }
        tokenT.setCompanyId(userCheckRequest.getCompanyID());
        tokenT.setSourceType(userCheckRequest.getType());
        return tokenT;
    }

    /**
     * 获取header参数信息
     * @param request
     * @return
     * @throws Exception
     */
    private UserOutSideTokenT getHeaderToken(HttpServletRequest request) throws Exception{
        UserOutSideTokenT tokenT = new UserOutSideTokenT();
        String token = request.getHeader("Authorization");
        String outSideId = request.getHeader("outSideId");
        String companyId = request.getHeader("companyId");
        String type = request.getHeader("type");
        if (StringUtils.isEmpty(token)) {
            throw new NotCheckException("token不能为空");
        }
        else if (StringUtils.isEmpty(outSideId)) {
            throw new NotCheckException("outSideId不能为空");
        }
        else if (StringUtils.isEmpty(companyId)) {
            throw new NotCheckException("渠道不能为空");
        }
        else if (StringUtils.isEmpty(type)) {
            throw new NotCheckException("类型不能为空");
        }
        tokenT.setToken(token);
        tokenT.setOutSideID(outSideId);
        tokenT.setCompanyId(Long.parseLong(companyId));
        tokenT.setSourceType(Integer.parseInt(type));
        return tokenT;
    }

    private String remoteInitToken(String username, String password) {
        //Url上包含%会报错，将其替换为%25
        password = password.replace("%", "%25");
        StringBuffer sb = new StringBuffer(this.propertiesUtils.getPropertiesValue("common.security.initToken")).append("?username=").append(username).append("&password=").append(password);
        Header accept = new BasicHeader("Accept", "application/json;odata=minimalmetadata");
        Header contentType = new BasicHeader("Content-Type", "application/json");
        String response = HttpUtils.get(sb.toString(), new ResponseHandler<String>() {
            @Override
            public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
                if (response.getStatusLine().getStatusCode() == 200) {
                    HttpEntity httpEntity = response.getEntity();
                    return EntityUtils.toString(httpEntity);
                } else {
                    log.error("远程初始化token异常，响应：" + response);
                }
                return null;
            }
        }, accept, contentType);
        if (StringUtils.isNotEmpty(response)) {
            log.info("远程初始化token信息：" + response);
            net.sf.json.JSONObject jsonObject = net.sf.json.JSONObject.fromObject(response);
            net.sf.json.JSONObject data = jsonObject.getJSONObject("data");
            if (null == data) {
                log.error("远程初始化token异常，响应：" + response);
                return null;
            } else {
                try {
                    return data.getString("token");
                } catch (Exception e) {
                    log.error("远程初始化token异常，响应：" + response);
                }
            }
        }
        return null;
    }


    private void mergeToken(Long userId, String adUserID, String token) {
        redisClientUtils.delkey(RedisKeys.tokenKey(token));
        UserTokenT userTokenT = userTokenTMapper.selectByAdUserId(adUserID);
        if (null != userTokenT) {
            userTokenT.setUserId(userId);
            userTokenTMapper.updateByPrimaryKeySelective(userTokenT);
            redisClientUtils.set(RedisKeys.tokenKey(userTokenT.getAccessToken()), JsonUtils.toJsonString(userTokenT), 3540);
        }
    }

    private Boolean validateVerifyCode(String phone, String verifyCode) {
        String redisCode = redisClientUtils.get("sms" + phone);
        if (StringUtils.isEmpty(redisCode) || !verifyCode.trim().equals(redisCode)) {
            return false;
        } else {
            //redisClientUtils.delkey("sms" + phone);
            return true;
        }
    }


    /**
     * 微信-注册前校验
     */
    @Override
    public void checkPhoneBeforeRegistWX(Map<String, Object> map) {
        log.info("注册-校验参数：" + map);

        // 获取加密的手机号
        String mobileEN = MapUtils.getString(map, "mobile", "");
        String openId = MapUtils.getString(map, "openId", "");
        Long companyID = MapUtils.getLong(map, "companyID");

        if (StringUtils.isBlank(mobileEN) || StringUtils.isBlank(openId)) {
            throw new RegistParameterException(51, "手机号或openId不能为空");
        }

        // 解密当前手机号
        String mobile = AESTool.decryptString(mobileEN);
        /**
         *  第一步：校验当前手机号是否已注册
         */
        UserT user = userTDao.checkUserByNameOrPhone(mobile);
        // 如果user为空说明当前手机号并未注册过
        if (!Objects.isNull(user)) {
            /**
             * 手机号已注册
             * 第二步：校验当前用户是否为终端用户(用户可能包含多个角色)
             *  R0002：为普通角色用户
             */
            int isContainsRoleNo = userTDao.isContainsRoleNo(user.getId(), "R0002");
            // 如果当前用户不包含该角色(R0002)，则不允许绑定微信账号
            if (isContainsRoleNo == 0) {
                throw new NonNormalUserException(31, "手机号已注册，但非普通用户角色");
            }

            /**
             * 校验手机号是否已绑定微信号
             */
//    		WeChatUserRelationT userRelation = weChatUserRelationTDao.selectByUserIdAndCompanyID(user.getId(), CompanyEnum.CCI.getId());
            if (null == companyID) {
                companyID = CompanyEnum.CCI.getId();
            }

            WeChatUserRelationT userRelation = weChatUserRelationTDao.selectByUserIdAndCompanyID(user.getId(), companyID);
            if (companyID == 3) {
                // userRelation为空说明当前用户未绑定微信公众号
                if (Objects.isNull(userRelation)) {
                    // 当前手机号未绑定当前公众号
                    throw new UserCheckException(11, "手机号已注册，未绑定公众号");
                } else {
                    // 手机号已绑定微信公众号
                    // 校验当前绑定的openId跟当前要绑定的openId是否相同
                    if (openId.equals(userRelation.getOpenID())) {
                        // 如果openId相同则返回异常  理论上是不会相同的
                        throw new UserCheckException(12, "手机号已注册，并且已绑定当前公众号");
                    } else {
                        // 当前手机号绑定了其它公众号
                        throw new UserCheckException(13, "手机号已注册，并且已绑定其它公众号");
                    }
                }
            } else {
                WeChatUserRelationT weChatUserRelationT = weChatUserRelationTDao.selectByOpenId(openId, companyID);
                if (Objects.isNull(userRelation) && Objects.isNull(weChatUserRelationT)) {
                    throw new UserCheckException(11, "手机号已注册，未绑定公众号");
                } else {
                    //根据user company 查出来的userRelation 与  根据 openId, companyID 查出来的 weChatUserRelationT 不同时
                    if (null != weChatUserRelationT && null != userRelation && weChatUserRelationT.getOpenID().equals(userRelation.getOpenID())) {
                        throw new UserCheckException(12, "手机号已注册，并且已绑定当前公众号");
                    } else {
                        // 如果openId相同则返回异常  理论上是不会相同的
                        throw new UserCheckException(13, "手机号已注册，并且已绑定其它公众号");
                    }
                }
            }
        }
    }

    @Override
    public void weChatLoginOut(HttpServletRequest request, HttpServletResponse response) throws Exception {
        WeChatLoginResponse loginResponse = new WeChatLoginResponse();
        String openId = request.getHeader("outSideId");
        String toke = request.getHeader("Authorization");
        String companyId = request.getHeader("companyId");
        Map<String,Object> msg = new HashMap<>();
        if (StringUtils.isBlank(openId) || StringUtils.isBlank(toke)) {
            msg.put("status",-99);
            msg.put("msg","outSideId或者Authorization 不能为空");
            ParameterTool.writeSuccessResponse(response, msg);
            return;
        }
        //删除用户信息
        String userKey = RedisKeys.outSideToken(Long.valueOf(companyId),1,openId);
        redisClientUtils.delkey(userKey);
        WeChatUserRelationT weChatUserRelationT = new WeChatUserRelationT();
        weChatUserRelationT.setUpdator(-1L);
        weChatUserRelationT.setUpdateTime(LocalTimeUtil.getRealCurrentTime());
        weChatUserRelationT.setOpenID(openId);
        weChatUserRelationTDao.updateStatusByOpenId(weChatUserRelationT);
        UserOutSideTokenT tokenT = userOutSideTokenTDao.selectByToken(openId, toke);
        //数据库中不存在则抛出异常
        if (tokenT == null || StringUtils.isBlank(tokenT.getOutSideID())) {
            msg.put("status",0);
            msg.put("msg","");
            ParameterTool.writeSuccessResponse(response, msg);
            return;
        }
        //去除 token
        userOutSideTokenTDao.updateDeleteFlag(tokenT.getId());
        redisClientUtils.delkey(RedisKeys.tokenKey(tokenT.getToken()));

        ParameterTool.writeSuccessResponse(response);
    }
}
